package com.sg.file.web;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.sg.common.model.ResultModel;
import com.sg.common.utils.ResultModelUtils;
import com.sg.file.common.FileCodeEnum;
import com.sg.file.common.conf.FileConfiguration;
import com.sg.file.common.conf.FileSizeTypeConf;
import com.sg.file.download.api.IFileDownloadService;
import com.sg.file.manager.api.IFileInfoService;
import com.sg.file.manager.repository.pojo.FileInfo;
import com.sg.file.receive.provider.util.creator.PathCreator;
import com.sg.file.transform.api.ITransformService;
import com.sg.file.transform.api.dto.TransformReqeust;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStream;
import java.nio.charset.Charset;

/**
 * Created by asus on 2018/7/16.
 */
@Slf4j
@CrossOrigin
@RestController
@RequestMapping("/file")
public class FileDownloadController {
    @Autowired
    private IFileInfoService fileInfoService;

    @Autowired
    private IFileDownloadService localFileDownload;

    @Autowired
    private FileConfiguration fileConfiguration;

    @Autowired
    private ITransformService transformService;

    private static final String NO_FILE_IN_PATH = "此路径下未找到文件";

    private static final String CONTENT_DISPOSITION ="Content-Disposition";

    private static final String BASE_CODE="gb2312";

    private static final String TARGET_CODE="ISO-8859-1";

    private static final String UTF8_CODE="UTF-8";

    private static final String DISPOSITION_FILENAME_NAME="attachment; filename=";

    /**
     * 根据文件的相对路径下载文件（老版本）
     * @param response
     * @param fileId
     * 			文件的相对路径
     * @param fileType
     * 			文件尺寸类型，此参数为约定参数，可在fileUploadConfig.properties中配置</br>
     * 			一旦配置成功后尽量不要修改
     *          默认类型有:
     *          			o  -  原始文件
     *      			    t  -  缩略图(视频和图片有此类型)
     *      			    s  -  小尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为小尺寸后，
     *                                  视频和图片的小尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比小尺寸还小，那么则会放大为此尺寸的像素)
     *      			    m  -  中等尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为中等尺寸后，
     *                                  视频和图片的中等尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比中等尺寸还小，那么则会放大为此尺寸的像素)
     *      			    l  -  原始寸默认转换格式后的文件
     *      							(如视频上传为avi格式，则会按照原尺寸转换为MP4格式存放在此处)
     * @throws Exception
     */
    @RequestMapping(value="/downloadById",method={RequestMethod.POST,RequestMethod.GET})
    public void downloadByIdOld(HttpServletResponse response
            , @RequestParam(value="fileId",required=false)String fileId
            , @RequestParam(value="fileType",required=false,defaultValue = FileSizeTypeConf.ORIGINAL)String fileType
            , @RequestParam(value="tranType",required=false)String tranType){
        downloadById(response,fileId,fileType,tranType);
    }

    /**
     * 根据文件的相对路径下载文件
     * @param response
     * @param fileId
     * 			文件的相对路径
     * @param fileSizeType
     * 			文件尺寸类型，此参数为约定参数，可在fileUploadConfig.properties中配置</br>
     * 			一旦配置成功后尽量不要修改
     *          默认类型有:
     *          			o  -  原始文件
     *      			    t  -  缩略图(视频和图片有此类型)
     *      			    s  -  小尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为小尺寸后，
     *                                  视频和图片的小尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比小尺寸还小，那么则会放大为此尺寸的像素)
     *      			    m  -  中等尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为中等尺寸后，
     *                                  视频和图片的中等尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比中等尺寸还小，那么则会放大为此尺寸的像素)
     *      			    l  -  原始寸默认转换格式后的文件
     *      							(如视频上传为avi格式，则会按照原尺寸转换为MP4格式存放在此处)
     * @param  suffixType  转换文件后缀类型
     * @throws Exception
     */
    @RequestMapping(value="/download",method={RequestMethod.POST,RequestMethod.GET})
    public void downloadById(HttpServletResponse response
            , @RequestParam(value="fileId",required=false)String fileId
            , @RequestParam(value="fileSizeType",required=false,defaultValue = FileSizeTypeConf.ORIGINAL)String fileSizeType
            , @RequestParam(value="suffixType",required=false)String suffixType){
        //需要进行转换
        boolean beTranseform = true;
        //获取文件信息
        FileInfo fileInfo = fileInfoService.getById(fileId);
        //如果为其他文件类型，则不需要进行转换，并且文件的后缀就为原本的文件后缀
        if(fileInfo.getFileType().equals("other")) {
            suffixType = fileInfo.getFileSuffix();
            //不需要进行转换
            beTranseform = false;

        }
        //获取文件路径
        suffixType = StringUtils.isEmpty(suffixType) ? fileConfiguration.getDefaultTransformSuffix(fileInfo.getFileType()) : suffixType;
        //生成文件路径
        String path = PathCreator.create(fileInfo, fileConfiguration.getPath().getBase(), fileSizeType, suffixType);
        if(beTranseform) {
            //进行转化
            boolean transformFlag = transeform(fileInfo,suffixType,fileSizeType);
            if (!transformFlag) {
                //如果转换是报错，则直接返回
                fileDownloadError(response, FileCodeEnum.FILE_TRANSFORM_FAIL);
                return;
            }
        }

        //验证文件是否存在,驗證必須放在文件转化之后
        File file = new File(path);
        if(!file.exists()){
            //如果不存在则获取源文件所在位置
            path = PathCreator.create(fileInfo, fileConfiguration.getPath().getBase(), FileSizeTypeConf.BACK_ORIGIN, suffixType);
        }
        //生成文件名
        String filename = fileInfo.getOriginalFileName()+"."+suffixType;
        try{
            response.setHeader(CONTENT_DISPOSITION,DISPOSITION_FILENAME_NAME
                    + new String(filename.getBytes(), TARGET_CODE));
        }catch(Exception e){
            log.error(e.getMessage());
        }

        try(OutputStream out = response.getOutputStream()){
            //文件写入输出流
            localFileDownload.wirte(out,path);
        } catch (FileNotFoundException e) {
            fileDownloadError(response, FileCodeEnum.NO_FILE_DOWNLOAD);
        } catch (IOException e) {
            log.error(e.getMessage());
            fileDownloadError(response, FileCodeEnum.FILE_DOWNLOAD_FAIL);
        }

    }

    /**
     * 文件转化
     * @param fileInfo 文件信息
     * @param suffixType 文件需要转换的后缀类型
     * @param fileSizeType 文件具体类型（指压缩类型）
     * @return
     */
    private boolean transeform(FileInfo fileInfo,String suffixType,String fileSizeType){
        //获取转换类
        String transformClassName = fileConfiguration.getDefaultTransformThumbnailClass(fileInfo.getFileType()) == null
                ? fileConfiguration.getDefaultTransformThumbnailClass(fileInfo.getFileType())
                : fileConfiguration.getDefaultTransformClass(fileInfo.getFileType());
        //转化请求信息
        TransformReqeust transformReqeust = TransformReqeust.toTransformRequest(fileInfo
                , suffixType, fileConfiguration.getPath().getBase(), fileSizeType
                , transformClassName);
        //文件转化
        return transformService.doTransformSync(transformReqeust);
    }

    /**
     * 根据文件的Id下载文件（Rest风格）
     * @param response
     * @param fileId
     * 			文件Id
     * @param fileType
     * 			文件尺寸类型，此参数为约定参数，可在fileUploadConfig.properties中配置</br>
     * 			一旦配置成功后尽量不要修改
     *          默认类型有:
     *          			o  -  原始文件
     *      			    t  -  缩略图(视频和图片有此类型)
     *      			    s  -  小尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为小尺寸后，
     *                                  视频和图片的小尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比小尺寸还小，那么则会放大为此尺寸的像素)
     *      			    m  -  中等尺寸(此尺寸为自定义尺寸，
     *      							一旦定义为中等尺寸后，
     *                                  视频和图片的中等尺寸则会按此尺寸压缩，
     *                                  如果原尺寸比中等尺寸还小，那么则会放大为此尺寸的像素)
     *      			    l  -  原始寸默认转换格式后的文件
     *      							(如视频上传为avi格式，则会按照原尺寸转换为MP4格式存放在此处)
     * @throws Exception
     */
    @RequestMapping(value= {"/rest/downloadById/{fileSizeType}/{fileId}",
            "/rest/{fileSizeType}/{fileId}"},method={RequestMethod.GET})
    public void restDownloadById(HttpServletResponse response
            ,@PathVariable("fileId")String fileId
            ,@PathVariable("fileSizeType")String fileType){
        downloadById(response,fileId,fileType,"");
    }

    private static void fileDownloadError(HttpServletResponse response,FileCodeEnum fileCodeEnum) {
        try {
            ObjectMapper mapper = new ObjectMapper();

            response.setHeader("Content-type", "application/Json;charset=UTF-8");
            ResultModel result = ResultModelUtils.getFailInstance(fileCodeEnum.getCode(),fileCodeEnum.getMessage());
            mapper.writeValue(response.getWriter(),result);
        } catch (IOException e) {
            log.error(e.getMessage());
        }
    }

}
